package com.demo.weather.server.handler;

import java.util.ArrayList;
import java.util.List;

import org.apache.commons.lang3.ArrayUtils;

import com.demo.weather.packet.Header;
import com.demo.weather.packet.Payload;
import com.demo.weather.packet.data.FunctionType;
import com.demo.weather.packet.data.PacketData;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.DecoderException;
import io.netty.handler.codec.ReplayingDecoder;
import lombok.extern.slf4j.Slf4j;

/**
 * 数据解码
 * @author tangheng
 */
@Slf4j
public class DecodeHandler extends ReplayingDecoder<DecodeHandler.DecodeState> {
	
    private Header header;
    private Payload payload;

    enum DecodeState {
        READ_HEADER,
        READ_PAYLOAD,
        READ_TAIL,
        BAD_MESSAGE
    }

    public DecodeHandler() {
        super(DecodeState.READ_HEADER);
    }

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        switch (state()) {
            case READ_HEADER:
                try {
                    header = decodeHeader(in);
                    checkpoint(DecodeState.READ_PAYLOAD);
                } catch (Exception cause) {
                    out.add(invalidMessage(cause));
                    return;
                }
            case READ_PAYLOAD:
            	try {
                    payload = decodePayload(in);
                    checkpoint(DecodeState.READ_HEADER);
                    
                    PacketData packetData = new PacketData(header, payload);

                    header = null;
                    payload = null;

                    out.add(packetData);
                    break;
                } catch (Exception cause) {
                    out.add(invalidMessage(cause));
                    return;
                }
            case BAD_MESSAGE:
                in.skipBytes(actualReadableBytes());
                checkpoint(DecodeState.READ_HEADER);
                break;
            default:
                throw new Error();
        }
    }

    /**解析头部*/
    protected Header decodeHeader(ByteBuf in) {
        byte startFlag = in.readByte();
        // 开始标志, 1个字节
        if (startFlag != Header.START_FLAG) {
            throw new DecoderException("packet format incorrect start flag: " + startFlag);
        }
        log.debug("开始标志: {}", String.format("%c", startFlag));

        /*
         * 记录仪编号, 2个字节
         */
        int grapherNo = in.readUnsignedShort();
        log.debug("记录仪编号: 0x{}", Integer.toHexString(grapherNo));

        /*
         * 功能码, 2个字节
         */
        int functionCode = in.readUnsignedShort();
        FunctionType functionType = FunctionType.valueOf(functionCode);
        log.debug("功能码: 0x{} -> {}", Integer.toHexString(functionCode), functionType);

        return new Header(grapherNo, functionType);
    }

    /**解析实际数据*/
    protected Payload decodePayload(ByteBuf in) {
    	// 每次读2个字节，遇到GG结束
    	List<Byte> content = new ArrayList<>();
    	byte[] temp2bytes = new byte[] {
    		in.readByte(), in.readByte()
    	};
    	while(temp2bytes[0]!=Payload.END_FLAG[0] || temp2bytes[1]!=Payload.END_FLAG[1]) {
    		content.add(temp2bytes[0]);
    		content.add(temp2bytes[1]);
    		temp2bytes = new byte[] {
        			in.readByte(), in.readByte()
        	};
    	}
    	
    	StringBuilder sb = new StringBuilder();
    	content.forEach(b->{
    		String hex = Integer.toHexString(b);
    		sb.append("0x").append(hex.length()>2?hex.substring(hex.length()-2):hex).append(" ");
    	});
    	log.debug("content N解析结束: {}", sb.toString());
    	
    	return new Payload(ArrayUtils.toPrimitive(content.toArray(new Byte[0])));
    }

    /**解码失败*/
    protected PacketData invalidMessage(Throwable cause) {
    	log.warn(cause.getMessage());
        checkpoint(DecodeState.BAD_MESSAGE);
    	return new PacketData(null, null);
    }
}